package ij.umasuo.AOTFController;

import ij.IJ;
import ij.ImagePlus;
import ij.umasuo.MyConstants;
import ij.umasuo.MyUserSettings;
import ij.umasuo.algorithms.AlgorithmManager;
import ij.umasuo.gui.laserCtr.storm.StormEditor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * use for the storm controller
 * @author liuquan
 * @date 2013-08-16
 * @version 1.0
 */
public class StormCtr extends Thread implements CtrInterface{
	
	private static AOTFClient aotfClient = AOTFClient.getInstance();
	private static StormCtr instance = null;
	private static boolean isTakingData = false;//to show if we are acquiring images
	private static boolean isLasersOn = false;// this use to show whether we have turn on the laser
	private static int maxCount = Integer.MAX_VALUE;
	private static Map<Integer,List<String>> images = new HashMap<Integer,List<String>>();//the images we got, and the key of images is the channel,we only keep the image path in memory, so we need less memory than before
	private static Map<Integer,Integer> imageIndex = new HashMap<Integer,Integer>();//the index of the images in each channel, we will use this when we process the images.
	private static Map<Integer,Integer> channelCount = new HashMap<Integer,Integer>();//the count for each channel
	private static int totalCount = 0;//the total image count we have got
	
	private static StormEditor sViewer = null;
	private StormCtr(){
	}
	public void setViewer(StormEditor viewer){
		sViewer = viewer;
	}
	@Override
	public void run() {
		while(isLasersOn || isTakingData){
			if(MyUserSettings.stCamera.size()<0){
				break;
			}
			int count = MyUserSettings.stCamera.size();
			for(int i=0;i<count;i++){
				String[] lasers = MyUserSettings.stLasers.get(i);
				List<String> powers = MyUserSettings.stLaserPower;
				List<String> cameras = MyUserSettings.stCamera;
				List<String> channel = MyUserSettings.stChannel;
				//lasers
				if(isLasersOn){
					for(int j=0;j<lasers.length;j++){
						if(lasers[j].equals("1")){
							aotfClient.Write("dds a " + j + " " + powers.get(j) + "\r");
						}else{
							aotfClient.Write("dds a " + j + " 0 \r");
						}
					}
				}
				//taking data
				if(isTakingData){
					if(cameras.get(i).equals("1")){
//						Object img = camera.snap();//only one image
						if(!channelCount.containsKey(new Integer(channel.get(i)))){
							channelCount.put(new Integer(channel.get(i)), new Integer(0));
						}
						IJ.runPlugIn("CameraPlugin", "storm:"+channel.get(i));//this method is blocked when 
						
					}
				}
			}
		}
	}

	
	/**
	 * power on the laser
	 */
	public void powerOnLasers(){
		if(instance == null){
			instance = new StormCtr();
		}
		aotfClient.resetAOTF();
		isLasersOn = true;
		if(instance.isAlive()){
			try {
				instance.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
		}
		instance = getNewInstance();
		instance.start();
	}
	
	/**
	 * power on the laser and we stop taking data at the same time
	 */
	public void powerOffLasers(){
		
		isLasersOn = false;
		try {
			instance.join();
		} catch (Exception e) {
			e.printStackTrace();
		}
		aotfClient.resetAOTF();
	}
	
	/**
	 * start taking data
	 */
	public void startTakingData(int maxCount){
		MyConstants.setFileSavePath();
		//before that we should clear all the data
		images.clear();
		imageIndex.clear();
		channelCount.clear();
		totalCount = 0;
		StormCtr.maxCount = maxCount;
		if(isLasersOn){//the thread already start
			isTakingData = true;
		}else{
			isLasersOn = true;
			isTakingData = true;
			instance = getNewInstance();
			instance.start();
		}
		
		AlgorithmManager.getInstance().setSourceModel(MyConstants.ALGORITHM_ONLINE);
		AlgorithmManager.getInstance().setOnlineImgSrouce(this);
		AlgorithmManager.getInstance().startProcessStorm();
	}
	
	/**
	 * stop taking data
	 */
	public void stopTakingData(){
		isTakingData = false;
	}
	
	public static StormCtr getInstance(){
		if(instance==null){
			instance = new StormCtr();
		}
		return instance;
	}

	public static StormCtr getNewInstance(){
		instance = new StormCtr();
		return instance;
	}
	public int getTotalCount(){
		return totalCount;
	}

	/**
	 * get the next image from one channel
	 * @param channel the channel we want to get
	 * @return
	 */
	public String getImageFromChannel(int channel){
		if(images.containsKey(new Integer(channel))){
			if(!imageIndex.containsKey(new Integer(channel))){
				imageIndex.put(new Integer(channel), new Integer(0));
			}
			int tmpIndex = imageIndex.get(new Integer(channel));
			List<String> tmpImages = images.get(new Integer(channel));
			if(tmpIndex >0 & tmpIndex< tmpImages.size()){
				String ret =  tmpImages.get(tmpIndex);
				tmpIndex++;
				imageIndex.put(new Integer(channel), tmpIndex);
				return ret;
			}
		}
		return null;
	}

	/**
	 * get one image form the channels
	 * @return
	 */
	public String getImage(){
		Integer[] channels = (Integer[])images.keySet().toArray();
		if(channels.length > 0){
			for(int i=0;i<channels.length;i++){//check all the channels, and return the first one we found
				String tmpImage = getImageFromChannel(channels[0]);
				if(tmpImage != null){
					return tmpImage;
				}
			}
		}
		return null;//we didn't find any images
	}
	
	/**
	 * add a image to the current
	 * @param imgPath
	 * @param channel
	 */
	public void addImage(String imgPath, int chan){
		if(!channelCount.containsKey(new Integer(chan))){
			channelCount.put(new Integer(chan), new Integer(0));
		}
		int chCount = channelCount.get(new Integer(chan));
		if(!images.containsKey(new Integer(chan))){
			images.put(new Integer(chan), new ArrayList<String>());
		}
		List<String> tmpImages = images.get(new Integer(chan));
		tmpImages.add(imgPath);
		chCount++;
		channelCount.put(new Integer(chan), new Integer(chCount));
		totalCount++;
		
		if(totalCount >= maxCount){
			isTakingData = false;//stop take data
			AlgorithmManager.getInstance().stopProcessStorm();
		}
	}
	public static boolean isTakingData(){
		return isTakingData;
	}
	public int getChanCount(int chan){
		if(!channelCount.containsKey(new Integer(chan))){
			channelCount.put(new Integer(chan), new Integer(0));
		}
		int chCount = channelCount.get(new Integer(chan));
		return chCount;
	}
	@Override
	public ImagePlus getNextImage() {
		// TODO Auto-generated method stub
		return null;
	}
	@Override
	public ImagePlus getNextImage(int channel) {
		// TODO Auto-generated method stub
		return null;
	}
	@Override
	public int getNextChannel() {
		// TODO Auto-generated method stub
		return 0;
	}
	@Override
	public int getNextFrame() {
		// TODO Auto-generated method stub
		return 0;
	}
	@Override
	public int getTotalImageCount() {
		// TODO Auto-generated method stub
		return 0;
	}
	@Override
	public String getNextImagePath() {
		// TODO Auto-generated method stub
		return null;
	}
	@Override
	public String getNextImagePath(int channel) {
		// TODO Auto-generated method stub
		return null;
	}
	
}
